# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
# This source file is part of the Cangjie project, licensed under Apache-2.0
# with Runtime Library Exception.
#
# See https://cangjie-lang.cn/pages/LICENSE for license information.


from os import path

float_ops = ['+', '-', '*', '/']
integer_ops = float_ops + ['%', '&', '|', '^'] #{ (i % 2 == 0, (i >> 1) % 2 == 0 ) }
integer_types = ['Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64']
float_types = ['Float16', 'Float32', 'Float64']

dir = path.dirname(path.realpath(__file__))
path = dir + '/test_' + path.basename(dir) + '_{}.cj'
template = '''
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * This source file is part of the Cangjie project, licensed under Apache-2.0
 * with Runtime Library Exception.
 *
 * See https://cangjie-lang.cn/pages/LICENSE for license information.
 */

/*
  @Assertion:   4.23(21) The compound assignment expression a op= b cannot be seen simply as a combination of an
                assignment expression and other binary operators a = a op b (where op can be any binary operator among
                arithmetic, logical and bitwise operators, and the operands a and b are of the type required by the
                operator op).
  @Description: %s
  @Mode: %s
  @Negative: %s
  @Structure: single
  @CompileWarning: ignore
  @Comment: Auto-generated by gen.py
  @Issue: 6428
*/
%s'''
positive_template = template % ('''Checks compilation and execution of a program that uses compound assignment expressions a op= b and
                compares them to regular assignments a = a op b. ''' , 'run', 'no', '''
from utils import utils.assert.Assert
from std import math.MathExtension
from std import random.Random
%s
@OverflowWrapping
main() {
    let rnd = Random(123)

    for (i in 0..4) {
        let t = (i %% 2 == 0, (i >> 1) %% 2 == 0)
        %s
    }

    for (_ in 0..1024) {
        %s

    }
}
''')
counter = 1
template_decl = '''
        let lhs{t1} = {}
        let rhs{} = {}
        var res{t1} : {t1}
'''
template_check = '''
        res{t1} = lhs{t1}
        res{t1} {}= rhs{t2}
        {}
'''
template_assert_equals = '''
func assertEquals(x : {t}, y : {t}) {{
    Assert.isTrue(x == y || (x.isNaN() && y.isNaN()) || (x.isInf() && y.isInf() && x * y > 0.0))
}}
'''

def write_counted(contents : str):
  global counter
  with open(path.format(str(counter).zfill(2)), 'w') as file:
    file.write(contents)
    counter += 1

def assert_equals(t1 : str, t2, op) -> str:
  prefix = 'assertEquals' if t1.startswith('Float') else 'Assert.equals'
  return prefix + '(lhs{t1} {op} rhs{t2}, res{t1})'.format(t1=t1, t2=t2, op=op)

def rand(ty : str) -> str:
  if ty.startswith('Float'): return 'rnd.next%s()' % ty
  return 'rnd.next{t}({t}.Max) + 1'.format(t=ty)

write_counted(positive_template % (
    ''.join([template_assert_equals.format(t=t) for t in float_types]),
    template_decl.format('t[0]', 'Bool', 't[1]', t1='Bool')
        + ''.join([template_check.format(op, assert_equals('Bool', 'Bool', op), t1='Bool', t2='Bool')
            for op in ['&&', '||']]),
    ''.join([template_decl.format(rand(t), t, rand(t), t1=t)
        + ''.join([template_check.format(op, assert_equals(t, t, op), t1=t, t2=t)
            for op in integer_ops])
        for t in integer_types])
    + ''.join([template_decl.format(rand(t).format(t=t), t, rand(t).format(t=t), t1=t)
        + ''.join([template_check.format(op, assert_equals(t, t, op), t1=t, t2=t)
            for op in float_ops])
        for t in float_types])
    + ''.join([template_check.format('**', assert_equals(t1, t2, '**'), t1=t1, t2=t2)
        for t1, t2 in [('Int64', 'UInt64'), ('Float64', 'Int64'), ('Float64', 'Float64')]])
    + ''.join(['\n        let rhsShift{t} = rnd.next{t}({})'.format(t[t.index('t')+1:], t=t)
        + ''.join([template_check.format(op, assert_equals(t, 'Shift' + t, op), t1=t, t2='Shift' + t) 
        for op in ['<<', '>>']]) for t in integer_types])
    ))
